package org.jeecg.modules.test.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.api.params.HeightLevelBadThingParams;
import org.jeecg.api.params.HeightLevelUserParams;
import org.jeecg.api.query.ElasticsearchQuery;
import org.jeecg.api.query.HeightLevelUserQuery;
import org.jeecg.api.vo.HeightLevelUserVO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.HeightLevelUserConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.BeanCopyUtils;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.modules.test.entity.HeightLevelBadThing;
import org.jeecg.modules.test.entity.HeightLevelUser;
import org.jeecg.modules.test.mapper.HeightLevelUserMapper;
import org.jeecg.modules.test.service.IElasticsearchCommonService;
import org.jeecg.modules.test.service.IHeightLevelBadThingService;
import org.jeecg.modules.test.service.IHeightLevelUserService;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * @author ZhangYu
 * @date 2023/9/24 23:45
 * @description 测试用户
 */
@Slf4j
@Service
public class HeightLevelUserServiceImpl extends ServiceImpl<HeightLevelUserMapper, HeightLevelUser> implements IHeightLevelUserService {

    @Resource
    private IHeightLevelBadThingService heightLevelBadThingService;
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private ISysBaseAPI sysBaseApi;
    @Resource
    private ElasticsearchClient elasticsearchClient;
    @Resource
    private IElasticsearchCommonService elasticsearchCommonService;

    private final ReentrantLock reentrantLock = new ReentrantLock();

    @Override
    public Page<HeightLevelUserVO> selectUserPage(@NotNull HeightLevelUserQuery heightLevelUserQuery) {
        Page<HeightLevelUser> heightLevelUserPage = baseMapper.selectPage(new Page<>(heightLevelUserQuery.getPageNo(), heightLevelUserQuery.getPageSize()), new QueryWrapper<HeightLevelUser>().lambda()
                .eq(StrUtil.isNotEmpty(heightLevelUserQuery.getName()), HeightLevelUser::getName, heightLevelUserQuery.getName())
        );
        return BeanCopyUtils.copyPage(heightLevelUserPage, HeightLevelUserVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUser(HeightLevelUserParams userParams) {
        HeightLevelUser user = BeanCopyUtils.copyNewBean(userParams, HeightLevelUser.class);
        user.setId(IdWorker.getId());
        List<HeightLevelBadThingParams> heightLevelBadThingList = Optional.ofNullable(userParams.getHeightLevelBadThingList()).orElse(Collections.emptyList());
        List<HeightLevelBadThing> newHeightLevelBadThingList = new ArrayList<>();
        for (HeightLevelBadThingParams heightLevelBadThingParams : heightLevelBadThingList) {
            HeightLevelBadThing heightLevelBadThing = BeanCopyUtils.copyNewBean(heightLevelBadThingParams, HeightLevelBadThing.class);
            heightLevelBadThing.setUserId(user.getId());
            newHeightLevelBadThingList.add(heightLevelBadThing);
        }
        //测试用户
        baseMapper.insert(user);
        elasticsearchCommonService.save(user, HeightLevelUserConstant.HEIGHT_LEVEL_USER_TABLE_NAME);
        //用户关联坏事
        heightLevelBadThingService.saveBatch(newHeightLevelBadThingList);
        elasticsearchCommonService.saveBatch(newHeightLevelBadThingList, HeightLevelUserConstant.HEIGHT_LEVEL_BAD_THING_TABLE_NAME);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {
        //测试用户
        baseMapper.deleteById(id);
        elasticsearchCommonService.removeById(id, HeightLevelUserConstant.HEIGHT_LEVEL_USER_TABLE_NAME);
        //用户关联坏事
        heightLevelBadThingService.remove(new QueryWrapper<HeightLevelBadThing>().lambda().eq(HeightLevelBadThing::getUserId, id));
        elasticsearchCommonService.remove(new ElasticsearchQuery().eq("user_id", id), HeightLevelUserConstant.HEIGHT_LEVEL_BAD_THING_TABLE_NAME);
    }

    @Override
    public String redisAddFind(String test) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        String oldData = valueOperations.get("test");
        log.info("-----------------------------------------------------------------------------老redis数据：{}", oldData);
        valueOperations.set("test", test, 5, TimeUnit.MINUTES);
        return valueOperations.get("test");
    }

    @Override
    public void lambdaTest() {
        List<HeightLevelUser> userList = baseMapper.selectList(new QueryWrapper<HeightLevelUser>().lambda().last("limit 10"));
        List<String> userNameList = userList.stream().map(HeightLevelUser::getName).collect(Collectors.toList());
        log.info("-------------------------------------------------------------------------用户姓名列表：{}", userNameList);
        List<HeightLevelUserVO> userVOList = userList.stream().map(user -> BeanUtil.copyProperties(user, HeightLevelUserVO.class)).collect(Collectors.toList());
        log.info("-------------------------------------------------------------------------用户返回值列表：{}", userVOList);
    }

    @Override
    public void addBigData() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        int num = 0;
        while (num < 1000) {
            List<HeightLevelUser> userList = new ArrayList<>();
            List<HeightLevelBadThing> heightLevelBadThingList = new ArrayList<>();
            for (int i = 0; i < 1000; i++) {
                Long userId = IdWorker.getId();
                userList.add(HeightLevelUser.builder().id(userId).age(18).six(0).birth(new Date()).build());
                heightLevelBadThingList.add(HeightLevelBadThing.builder().id(IdWorker.getId()).userId(userId).heightLevelName("干坏事").build());
            }
            super.saveBatch(userList);
            heightLevelBadThingService.saveBatch(heightLevelBadThingList);
            userList.clear();
            heightLevelBadThingList.clear();
            num++;
        }
        stopWatch.stop();
        double totalTimeMillis = stopWatch.getTotalTimeSeconds();
        log.info("---------------------------------------------------------------------------总耗时：{}", totalTimeMillis);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void longRangeTest() {
        Result<?> departListResult = sysBaseApi.getDepartList();
        log.info("--------------------------------------------------------------接收到：{}", departListResult.getResult());
    }

    @Override
    public synchronized void testSynchronized(Long id) {
        HeightLevelUser heightLevelUser = baseMapper.selectOne(new QueryWrapper<HeightLevelUser>().lambda().eq(HeightLevelUser::getId, id));
        Integer newAge = heightLevelUser.getAge() + 1;
        super.update(new UpdateWrapper<HeightLevelUser>().lambda().set(HeightLevelUser::getAge, newAge).eq(HeightLevelUser::getId, id));
    }

    @Override
    public void testReentrantLock(Long id) {
        reentrantLock.lock();
        try {
            HeightLevelUser heightLevelUser = baseMapper.selectOne(new QueryWrapper<HeightLevelUser>().lambda().eq(HeightLevelUser::getId, id));
            Integer newAge = heightLevelUser.getAge() + 1;
            super.update(new UpdateWrapper<HeightLevelUser>().lambda().set(HeightLevelUser::getAge, newAge).eq(HeightLevelUser::getId, id));
        } finally {
            reentrantLock.unlock();
        }
    }

    @Override
    public Page<HeightLevelUserVO> testElasticsearchPage(Integer pageNo, Integer pageSize) {
        //Elasticsearch查询分页信息
        SearchResponse<Object> searchResponse;
        try {
            searchResponse = elasticsearchClient.search(builder -> builder.index(HeightLevelUserConstant.HEIGHT_LEVEL_USER_TABLE_NAME)
                    .from(CommonUtils.getFormNumber(pageNo, pageSize)).size(pageSize)
                    .trackTotalHits(t -> t.enabled(true)), Object.class);
        } catch (IOException e) {
            throw new JeecgBootException("Elasticsearch查询出现异常", e);
        }
        //封装到Page分页
        return elasticsearchCommonService.setPageInfo(pageNo, pageSize, searchResponse, HeightLevelUserVO.class);
    }

}
